package daoimpl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

import ucc.Service;
import uccimpl.PersonService;
import util.Utils;
import nu.xom.Attribute;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import dao.Dao;
import domain.Debt;
import domain.Person;
import exceptions.InvalidParameterException;

public class DebtDaoImpl extends Dao<Debt> {
	
	private Service<Person> personService = PersonService.getInstance();	
	private String currentMonth;
	
	public DebtDaoImpl() {
		super("xmlDB/debts.xml", "xmlDB/idSequence.xml");
		currentMonth = Utils.currentMonth();
	}

	@Override
	public Debt add(Debt debt) {
		debt.setId(this.idSequence++);
		Element currentMonthElement = getCurrentMonthElement();
		currentMonthElement.appendChild(debtToElement(debt));
		documentChanged = true;
		return debt;
	}

	@Override
	public Debt find(int id) {
		Elements dates = document.getRootElement().getChildElements();
		for (int i = 0; i < dates.size(); i++) {
			Element month = dates.get(i);
			Elements monthDebts = month.getChildElements();
			for (int j = 0; j < monthDebts.size(); j++) {
				Element debt = monthDebts.get(j);
				if (Integer.parseInt(debt.getAttribute("id").getValue()) == id)
					return elementToDebt(debt);
			}
		}
		return null;
	}

	public ArrayList<Debt> findDebtBySource(Person source) {
		ArrayList<Debt> results = new ArrayList<Debt>();
		Elements dates = document.getRootElement().getChildElements();
		for (int i = 0; i < dates.size(); i++) {
			Element month = dates.get(i);
			Elements monthDebts = month.getChildElements();
			for (int j = 0; j < monthDebts.size(); j++) {
				Element debt = monthDebts.get(j);
				if (Integer.parseInt(debt.getChildElements("source").get(0).getValue()) == source.getId()) {
					results.add(elementToDebt(debt));
				}
			}
		}
		return results;
	}

	public Debt remove(int id) {
		Elements dates = document.getRootElement().getChildElements();
		for (int i = 0; i < dates.size(); i++) {
			Element month = dates.get(i);
			Elements monthDebts = month.getChildElements();
			for (int j = 0; j < monthDebts.size(); j++) {
				Element debt = monthDebts.get(j);
				if (Integer.parseInt(debt.getAttribute("id").getValue()) == id) {
					document.removeChild(debt);
					this.documentChanged = true;
					return elementToDebt(debt);
				}
			}
		}
		return null;
	}

	public ArrayList<Debt> findDebtByOwedTo(Person owedTo) {
		ArrayList<Debt> results = new ArrayList<Debt>();
		Elements dates = document.getRootElement().getChildElements();
		for (int i = 0; i < dates.size(); i++) {
			Element month = dates.get(i);
			Elements monthDebts = month.getChildElements();
			for (int j = 0; j < monthDebts.size(); j++) {
				Element debt = monthDebts.get(j);
				if (Integer.parseInt(debt.getChildElements("owedTo").get(0).getValue()) == owedTo.getId()) {
					results.add(elementToDebt(debt));
				}
			}
		}
		return results;
	}

	@Override
	public Debt update(Debt debt) {
		Elements dates = document.getRootElement().getChildElements();
		for (int i = 0; i < dates.size(); i++) {
			Element month = dates.get(i);
			Elements monthDebts = month.getChildElements();
			for (int j = 0; j < monthDebts.size(); j++) {
				Element debtElem = monthDebts.get(j);
				if (Integer.parseInt(debtElem.getAttribute("id").getValue()) == debt.getId()) {
					document.replaceChild(debtElem, debtToElement(debt));
					return debt;
				}
			}
		}
		return null;
	}
	
	@Override
	public ArrayList<Debt> listAll() {
		ArrayList<Debt> allDebts = new ArrayList<Debt>();
		Elements dates = document.getRootElement().getChildElements();
		for (int i = 0; i < dates.size(); i++) {
			Element month = dates.get(i);
			Elements monthDebts = month.getChildElements();
			for (int j = 0; j < monthDebts.size(); j++) {
				allDebts.add(elementToDebt(monthDebts.get(j)));
			}
		}
		return allDebts;
	}

	public ArrayList<Debt> getAllDebtsForMonth(String month) {
		ArrayList<Debt> allDebts = new ArrayList<Debt>();
		Element monthElem = getCurrentMonthElement();
		Elements monthDebts = monthElem.getChildElements();
		for (int i = 0; i < monthDebts.size(); i++) {
			allDebts.add(elementToDebt(monthDebts.get(i)));
		}
		return allDebts;
	}
	
	private Debt elementToDebt(Element e) {
		Debt debt = new Debt();
		int id = Integer.parseInt(e.getAttribute("id").getValue());
		double amount = Double.parseDouble(e.getChildElements("amount").get(0).getValue());
		String comment = e.getChildElements("comment").get(0).getValue();
		String date = e.getChildElements("date").get(0).getValue();
		Person owedTo = null;
		try {
			owedTo = personService.find(Integer.parseInt(e.getChildElements("owedTo").get(0).getValue()));
		} catch (NumberFormatException e1) {
			e1.printStackTrace();
		} catch (InvalidParameterException e1) {
			e1.printStackTrace();
		}
		Person source = null;
		try {
			source = personService.find(Integer.parseInt(e.getChildElements("source").get(0).getValue()));
		} catch (NumberFormatException e1) {
			e1.printStackTrace();
		} catch (InvalidParameterException e1) {
			e1.printStackTrace();
		}
		boolean done = e.getChildElements("done").get(0).getValue().equals("true");
		String dateDone = e.getChildElements("dateDone").get(0).getValue();
		
		debt.setAmount(amount);
		debt.setComment(comment);
		debt.setDate(date);
		debt.setId(id);
		debt.setOwedTo(owedTo);
		debt.setSource(source);
		debt.setDateDone(dateDone);
		debt.setDone(done);
		return debt;
	}
	
	private Element debtToElement(Debt debt) {
		Element e = new Element("debt");
		e.addAttribute(new Attribute("id", ""+debt.getId()));
		Element amount = new Element("amount");
		amount.appendChild(""+debt.getAmount());
		Element comment = new Element("comment");
		comment.appendChild(debt.getComment());
		Element date = new Element("date");
		date.appendChild(debt.getDate());
		Element owedTo = new Element("owedTo");
		owedTo.appendChild(debt.getOwedTo().getId()+"");
		Element source = new Element("source");
		source.appendChild(debt.getSource().getId()+"");
		Element done = new Element("done");
		done.appendChild(debt.isDone()+"");
		Element dateDone = new Element("dateDone");
		dateDone.appendChild(debt.getDateDone());
		e.appendChild(amount);
		e.appendChild(comment);
		e.appendChild(date);
		e.appendChild(owedTo);
		e.appendChild(source);
		e.appendChild(done);
		e.appendChild(dateDone);
		
		return e;
	}

	private Element getCurrentMonthElement() {
		//loop through root element children to find current month element
		Elements el = this.document.getRootElement().getChildElements();
		for (int i = 0; i < el.size(); i++) {
			Element e = el.get(i);
			if (e.getAttribute("monthyear").getValue().equals(currentMonth)) {
				return e;
			}
		}
		// nothing found, create new element
		String currentMonth = Utils.currentMonth();
		Element newMonth = new Element("date");
		newMonth.addAttribute(new Attribute("monthyear", currentMonth));
		this.getDocument().getRootElement().appendChild(newMonth);
		this.setCurrentMonth(currentMonth);
		this.setDocumentChanged(true);
		return newMonth;
	}
	
	public String getCurrentMonth() {
		return currentMonth;
	}

	private void setCurrentMonth(String currentMonth) {
		this.currentMonth = currentMonth;
	}
	
	public Document getDocument() {
		return document;
	}
}